#include <stdlib.h>
#include <stdio.h>
#include <vector>
#include <string>

#include "OldParser.h"
#include "Parser.h"

static void KillNewLines(char *sp);
static void LoadTokens(char *file);
static void Test(const char *tokens, const char *file, const char *output, int);

static int CloseF = 0;

void RunTests(void)
{
  char *buffer;
  int   i;
  int   bufsize;
  std::vector<std::string> fldrs;

  printf("------------------- Running Data/Tests.txt Tests -------------------\n");

  OldParser::ParserInit("Data/Tests.txt", 1024);
  OldParser::AddTokenSeparator("\n", 0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator("\r", 0, -1, 0, 0, 0);

  for(buffer = OldParser::GrabToken(); buffer; buffer = OldParser::GrabToken())
  {
    fldrs.push_back(std::string(buffer));
    free(buffer);
  }

  OldParser::ParserDeInit();

  for(CloseF = 0; CloseF <= 1; ++CloseF)
  {
    if(CloseF)
      printf("------------------- Closed File When Done:\n");
    else
      printf("------------------- Left File Open:\n");
    for(i = 0; i < (int)fldrs.size(); ++i)
    {
      printf("Testing: %s\n", fldrs[i].c_str());
      for(bufsize = 0; bufsize < 1024; ++bufsize)
      {
        Test((fldrs[i] + "/Tokens.txt").c_str(),
             (fldrs[i] + "/Test.txt").c_str(),
             (fldrs[i] + "/Output.txt").c_str(),
             bufsize);
             //break;
           }
           //break;
    }
  }
}


void Test(const char *tokens, const char *file, const char *output, int bufsize)
{
  char *buffer;
  char *expected;
  int   error = 0;
  int   tnum  = 0;

  ParserInit((char *)file, bufsize);
  if(CloseF) ParserEnable(PARSER_CLOSE_FILE);
  LoadTokens((char *)tokens);

  OldParser::ParserInit((char *)output, 1024);
  OldParser::AddTokenSeparator("\n", 0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator("\r", 0, -1, 0, 0, 0);

  for(buffer = GrabToken(); buffer; buffer = GrabToken())
  {
    ++tnum;
    expected = OldParser::GrabToken();
    if(!OldParser::Cmp(buffer, expected))
    {
      KillNewLines(buffer);
      printf("%15s: %4d: %4d: |%55s| != |%55s|\n", file, bufsize, tnum, expected, buffer);
      error = 1;
    }
    else
    {
      //KillNewLines(buffer);
      //printf("%15s: %4d: |%55s| == |%55s|\n", file, bufsize, expected, buffer);
    }

    free(buffer);
    if(expected)
      free(expected);
  }

  expected = OldParser::GrabToken();
  if(OldParser::ErrorCode() != ErrorCode())
  {
    printf("%15s: %4d: Early Termination\n", file, bufsize);
    OldParser::PrintErrorCode();
    PrintErrorCode();
  }

  ParserDeInit();
  OldParser::ParserDeInit();

  if(error)
    printf("%15s: %4d: Failed\n", file, bufsize);
}

static int PushHash (void *);
static int PushIns  (void *);
static int PushWild (void *);
static int PushRegEx(void *);
static int PushTSet (void *);
static int SetTSet  (void *);
static int PushToken(void *);

void LoadTokens(char *file)
{
  char *buffer;

  OldParser::ParserInit(file, 1024);
  OldParser::AddTokenSeparator("(",    0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator(")",    0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator(";",    0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator(",",    0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator(" ",    0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator("\t",   0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator("\n",   0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator("\r",   0, -1, 0, 0, 0);
  OldParser::AddTokenSeparator("//",   0,  1, 0, (int (*)())OldParser::GenericDiscard, 0);
  OldParser::AddTokenSeparator("/*",   0,  2, 0, (int (*)())OldParser::GenericDiscard, 0);
  OldParser::AddTokenSeparator("\"",   0,  3, 0, 0, 0);

  OldParser::AddTokenSeparator("PARSER_HASH",         0, -1, 0, (int(*)())PushHash,  0);
  OldParser::AddTokenSeparator("PARSER_CASE_INSENSITIVE", 0, -1, 0, (int(*)())PushIns,   0);
  OldParser::AddTokenSeparator("PARSER_WILDCARD",         0, -1, 0, (int(*)())PushWild,  0);
  OldParser::AddTokenSeparator("PARSER_REGEX",            0, -1, 0, (int(*)())PushRegEx, 0);
  OldParser::AddTokenSeparator("AddTokenSet",             0, -1, 0, (int(*)())PushTSet,  0);
  OldParser::AddTokenSeparator("SetTokenSet",             0, -1, 0, (int(*)())SetTSet,   0);
  OldParser::AddTokenSeparator("Token",                   0, -1, 0, (int(*)())PushToken, 0);
  OldParser::AddTokenSeparator("AddTokenSeparator",       0, -1, 0, (int(*)())PushToken, 0);

  OldParser::AddTokenSet();
  OldParser::AddTokenSeparator("\n",   0,  0, 0, 0, 0);
  OldParser::AddTokenSeparator("\r",   0,  0, 0, 0, 0);

  OldParser::AddTokenSet();
  OldParser::AddTokenSeparator("*/",   0,  0, 0, 0, 0);

  OldParser::AddTokenSet();
  OldParser::AddTokenSeparator("\\\"", 0, -1, 1, 0, 0);
  OldParser::AddTokenSeparator("\"",   0,  0, 0, 0, 0);

  OldParser::SetTokenSet(0);

  for(buffer = OldParser::GrabToken(); buffer; buffer = OldParser::GrabToken())
  {
    printf("%15s: Unknown Token: |%s|\n", file, buffer);
    free(buffer);
  }

  OldParser::ParserDeInit();
}


int PushHash(void *){ParserEnable(PARSER_HASH);             return 0;}
int PushIns (void *){ParserEnable(PARSER_CASE_INSENSITIVE); return 0;}
int PushWild(void *){ParserEnable(PARSER_WILDCARD);         return 0;}
int PushRegEx(void*){ParserEnable(PARSER_REGEX);            return 0;}
int PushTSet(void *){AddTokenSet();                         return 0;}
int SetTSet (void *){SetTokenSet(OldParser::GrabInt());            return 0;}

int PushToken(void *)
{
  int   read, write;
  char *token = OldParser::GrabToken();
  int   ret   = OldParser::GrabInt();
  int   sto   = OldParser::GrabInt();
  int   ign   = OldParser::GrabInt();
  int   dis   = OldParser::GrabInt();

  for(read = 0, write = 0; token[read]; ++read)
    switch(token[read])
    {
      case '\\':
             if(token[read + 1] == 'n') {token[write++] = '\n'; ++read; break;}
        else if(token[read + 1] == 'r') {token[write++] = '\r'; ++read; break;}
        else if(token[read + 1] == 't') {token[write++] = '\t'; ++read; break;}
        else if(token[read + 1] == '\"'){token[write++] = '\"'; ++read; break;}
        else if(token[read + 1] == '\\'){token[write++] = '\\'; ++read; break;}
        else if(token[read + 1] == '\''){token[write++] = '\''; ++read; break;}
        else if(token[read + 1] == '\0'){token[write++] = '\0'; ++read; break;}

      default:
        token[write++] = token[read];
    }

  token[write] = 0;

  //printf("Token: |%s| %d %d %d %d\n", token, ret, sto, ign, dis);

  if(dis)
    AddTokenSeparator(token, (char)ret, (char)sto, (char)ign, GenericDiscard,0);
  else
    AddTokenSeparator(token, (char)ret, (char)sto, (char)ign, 0, 0);

  free(token);

  return 0;
}

void KillNewLines(char *sp)
{
  int read;
  int write;

  for(read = 0, write = -1; sp[read]; ++read)
    switch(sp[read])
    {
      case '\n':
      case '\r':
        sp[++write] = '|';
        break;
      default:
        sp[++write] = sp[read];
        break;
    }
  sp[++write] = 0;
}
